/*
 * @Author: 肖思汗 
 * @Date: 2025-06-16 14:03:44 
 * @Last Modified by: xiaosihan
 * @Last Modified time: 2025-09-25 14:31:43
 */

// @ts-nocheck

import Taro from '@tarojs/taro';
import EventTarget from '../libs/EventTarget';

const _requestHeader = new WeakMap();
const _responseHeader = new WeakMap();
const _requestTask = new WeakMap();

function _triggerEvent(type, event = {}) {
    event.target = event.target || this;

    if (typeof this[`on${type}`] === 'function') {
        this[`on${type}`].call(this, event);
    }
}

function _changeReadyState(readyState, event = {}) {
    this.readyState = readyState;

    event.readyState = readyState;

    _triggerEvent.call(this, 'readystatechange', event);
}

function _isRelativePath(url) {
    return !/^(http|https|ftp|wxfile):\/\/.*/i.test(url);
}

let platform = 'unknown';
try {
    const deviceInfo = Taro.getDeviceInfo();
    platform = deviceInfo.platform;
} catch (error) {
    console.warn('获取设备信息失败，使用默认平台值:', error);
}

export default class $XMLHttpRequest extends EventTarget {
    constructor() {
        super();

        /*
         * TODO 这一批事件应该是在 XMLHttpRequestEventTarget.prototype 上面的
         */
        this.onabort = null;
        this.onerror = null;
        this.onload = null;
        this.onloadstart = null;
        this.onprogress = null;
        this.ontimeout = null;
        this.onloadend = null;

        this.onreadystatechange = null;
        this.readyState = 0;
        this.response = null;
        this.responseText = null;
        this.responseType = 'text';
        this.dataType = 'string';
        this.responseXML = null;
        this.status = 0;
        this.statusText = '';
        this.upload = {};
        this.withCredentials = false;

        _requestHeader.set(this, {
            'content-type': 'application/x-www-form-urlencoded',
        });
        _responseHeader.set(this, {});
    }

    abort() {
        const myRequestTask = _requestTask.get(this);

        if (myRequestTask) {
            myRequestTask.abort();
        }
    }

    getAllResponseHeaders() {
        const responseHeader = _responseHeader.get(this);

        return Object.keys(responseHeader)
            .map(header => {
                return `${header}: ${responseHeader[header]}`;
            })
            .join('\n');
    }

    getResponseHeader(header) {
        return _responseHeader.get(this)[header];
    }

    open(method, url /* async, user, password 这几个参数在小程序内不支持*/) {
        this._method = method;
        this._url = url;
        _changeReadyState.call(this, $XMLHttpRequest.OPENED);
    }

    overrideMimeType() { }

    send(data = '') {
        if (this.readyState !== $XMLHttpRequest.OPENED) {
            throw new Error(
                "Failed to execute 'send' on 'XMLHttpRequest': The object's state must be OPENED.",
            );
        } else {
            const url = this._url;
            const header = _requestHeader.get(this);
            const responseType = this.responseType;
            const dataType = this.dataType;

            const relative = _isRelativePath(url);
            let encoding;

            if (responseType === 'arraybuffer') {
                // encoding = 'binary'
            } else {
                encoding = 'utf8';
            }

            delete this.response;
            this.response = null;
            let resolved = false

            const onSuccess = ({ data, statusCode, header }) => {
                // console.log('onSuccess', url)
                if (resolved) return
                resolved = true;
                statusCode = statusCode === undefined ? 200 : statusCode;
                if (typeof data !== 'string' && !(data instanceof ArrayBuffer)) {
                    try {
                        data = JSON.stringify(data);
                    } catch (e) { }
                }

                this.status = statusCode;
                if (header) {
                    _responseHeader.set(this, header);
                }
                _triggerEvent.call(this, 'loadstart');
                _changeReadyState.call(this, $XMLHttpRequest.HEADERS_RECEIVED);
                _changeReadyState.call(this, $XMLHttpRequest.LOADING);

                this.response = data;

                if (data instanceof ArrayBuffer) {
                    Object.defineProperty(this, 'responseText', {
                        enumerable: true,
                        configurable: true,
                        get: function () {
                            throw 'InvalidStateError : responseType is ' + this.responseType;
                        },
                    });
                } else {
                    this.responseText = data;
                }
                _changeReadyState.call(this, $XMLHttpRequest.DONE);
                _triggerEvent.call(this, 'load');
                _triggerEvent.call(this, 'loadend');
            };

            const onFail = ({ errMsg }) => {
                // 规范错误
                if (resolved) return
                resolved = true;
                if (errMsg.indexOf('abort') !== -1) {
                    _triggerEvent.call(this, 'abort');
                } else {
                    _triggerEvent.call(this, 'error', {
                        message: errMsg,
                    });
                }
                _triggerEvent.call(this, 'loadend');

                if (relative) {
                    // 用户即使没监听error事件, 也给出相应的警告
                    console.warn(errMsg);
                }
            };

            if (relative) {
                const fs = wx.getFileSystemManager();

                var options = {
                    filePath: url,
                    success: onSuccess,
                    fail: onFail,
                };
                if (encoding) {
                    options['encoding'] = encoding;
                }
                fs.readFile(options);
                return;
            }

            // IOS在某些情况下不会触发onSuccess...
            const usePatch = responseType === 'arraybuffer' && platform === 'ios' && $XMLHttpRequest.useFetchPatch;

            wx.request({
                data,
                url: url,
                method: this._method,
                header: header,
                dataType: dataType,
                responseType: responseType,
                enableCache: false,
                success: onSuccess,
                // success: usePatch ? undefined : onSuccess,
                fail: onFail,
            });

            if (usePatch) {
                setTimeout(function () {
                    wx.request({
                        data,
                        url: url,
                        method: this._method,
                        header: header,
                        dataType: dataType,
                        responseType: responseType,
                        enableCache: true,
                        success: onSuccess,
                        fail: onFail,
                    });
                }, $XMLHttpRequest.fetchPatchDelay)
            }
        }
    }

    setRequestHeader(header, value) {
        const myHeader = _requestHeader.get(this);

        myHeader[header] = value;
        _requestHeader.set(this, myHeader);
    }

    addEventListener(type, listener) {
        if (typeof listener !== 'function') {
            return;
        }

        this['on' + type] = (event = {}) => {
            event.target = event.target || this;
            listener.call(this, event);
        };
    }

    removeEventListener(type, listener) {
        if (this['on' + type] === listener) {
            this['on' + type] = null;
        }
    }
}

// 没法模拟 HEADERS_RECEIVED 和 LOADING 两个状态
$XMLHttpRequest.UNSEND = 0;
$XMLHttpRequest.OPENED = 1;
$XMLHttpRequest.HEADERS_RECEIVED = 2;
$XMLHttpRequest.LOADING = 3;
$XMLHttpRequest.DONE = 4;

// 某些情况下IOS会不success不触发。。。
$XMLHttpRequest.useFetchPatch = false;
$XMLHttpRequest.fetchPatchDelay = 200;